
#include "Card.h"
#include "CardPrivate.h"
#include "Contactless/ISO14443p3a.h"
#include "Contactless/ISO14443p4a.h"
#include "CardCpuA.h"
#include "CardCpuPrivate.h"

#include "Mem.h"

static const CpuCardOps_T cpuCardAOps;

static CpuCard_T cpuCard;
static ISO14443AInfo_T cpuInfoA;

static void Card_CpuA_Init(Card_T* card, WCI* wci, void* info){
	card->type = Card_T_CpuA;
	card->wci = wci;
	card->ops = &cpuCardAOps;
	card->pdata = info;
}

#if 0
static Card_T* Card_CpuA_Create(WCI* wci) {
	Card_T* card = (Card_T*)Memory_Alloc(sizeof(CpuCard_T));
	if(card){
		ISO14443AInfo_T* info = (ISO14443AInfo_T*)Memory_Alloc(sizeof(ISO14443AInfo_T));
		if(info){
			Card_CpuA_Init(card, wci, (void*)info);
		}
		else{
			Memory_Free(card);
			card = (Card_T*)0;
		}
	}
	return card;
}

static void Card_CpuA_Destroy(Card_T* card) {
	if(card){
		Memory_Free(card->pdata);
		Memory_Free(card);
	}
}

#endif

static Card_T* Card_CpuA_Create(WCI* wci) {
	Card_CpuA_Init((Card_T*)&cpuCard, wci, (void*)&cpuInfoA);
	return (Card_T*)&cpuCard;
}

static void Card_CpuA_Destroy(Card_T* card) {
	(void)card;
}

const CardFactory_T cpuCardFactoryA = {
	.init = Card_CpuA_Init,
	.create = Card_CpuA_Create,
	.destroy = Card_CpuA_Destroy,
};

static int Card_CpuA_Probe(Card_T* card) {
	unsigned char dummy[2];
	int ret = ISO14443A_RequestA(card->wci, dummy);
	return ret == WCI_S_OK || ret == WCI_S_Coll;
}

static int Card_CpuA_Activate(Card_T* card) {
	int ret = ISO14443A_Activate(card->wci, PICC_Op_Wakeup, (ISO14443AInfo_T*)card->pdata);
	if (ret == 0) {
		card->state = 1;
	}
	return ret;
}

static int Card_CpuA_Deactivate(Card_T* card) {
	int ret = ISO14443A_Halt(card->wci, 0);
	card->state = 0;
	return ret;
}

static int Card_CpuA_Exchange(Card_T* card, 
	unsigned char capdu[], unsigned int clen, unsigned char rapdu[], unsigned int* rlen) {
	CpuCard_T* cpuCard = (CpuCard_T*)card;

	return ISO14443p4_Exchange(cpuCard, capdu, clen, rapdu, rlen);
}

static int Card_CpuA_Setup(Card_T* card, uint8_t cid, uint8_t fsdi, void *param, uint8_t ats[]) {
	CpuCard_T* cpuCard = (CpuCard_T*)card;
	ISO14443p4Param_T* params = &cpuCard->params;

	int ret = ISO14443p4a_RATS(card->wci, cid, fsdi, ats);
	if (ret) {
		return ret;
	}
	ISO14443p4a_GetParams(ats, params);
	params->CID = cid;
	card->state = 2;
	return ret;
}

static int Card_CpuA_Teardown(Card_T* card) {
	CpuCard_T* cpuCard = (CpuCard_T*)card;
	int ret = ISO14443p4_Deselect(cpuCard);
	card->state = 0;
	return ret;
}

static int Card_CpuA_Check(Card_T* card){
	return ISO14443_CheckPresence((CpuCard_T*)card);
}


static const CpuCardOps_T cpuCardAOps = {
	.probe = Card_CpuA_Probe,
	.activate = Card_CpuA_Activate,
	.deactivate = Card_CpuA_Deactivate,
	.exchange = Card_CpuA_Exchange,
	.teardown = Card_CpuA_Teardown,
	.setup = Card_CpuA_Setup,
	.check = Card_CpuA_Check,	
};
	
